package com.juyu.miliao.api.util;

import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;

import static java.util.stream.Collectors.toList;

/**
 * @author zc
 * @date 18-11-20下午7:03
 */
public class SegmentedLock {
    private static final int DEFAULTS_LOCK_SIZE = 17;
    private final List<Lock> locks;
    private final int capacity;

    public SegmentedLock(int capacity) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.capacity = capacity;
        locks = IntStream.range(0, capacity)
                .mapToObj(index -> new ReentrantLock())
                .collect(toList());
    }

    public SegmentedLock() {
        this(DEFAULTS_LOCK_SIZE);
    }

    private int computeSlot(Object key){
        return Math.abs(key.hashCode()) % capacity;
    }

    public Lock getLock(Object key) {
        return locks.get(computeSlot(key));
    }

    public void doInSync(Object key, Runnable operate){
        Lock lock = getLock(key);
        lock.lock();
        try {
            operate.run();
        } finally {
            lock.unlock();
        }
    }

}
